#include <common/HeaderSpace.h>
#include <folly/Conv.h>
#include <folly/futures/Future.h>
#include <folly/logging/xlog.h>
#include <normalizer/Normalizer.h>

#include <range/v3/view/chunk.hpp>
#include <sylvan_obj.hpp>
#include <tbb/parallel_for.h>
#include <future>

namespace flashpp {
// std::vector<sylvan::Mtbdd> Normalizer::vars = {};

// TODO: destruct executor_
Normalizer::Normalizer(Pipeline& pipeline) : executor_(2) {
  addFiberTask([&pipeline, this]() mutable noexcept {
    while (1) {
      std::shared_ptr<DataPlaneUpdate> dpu;
      auto ticket = pipeline.blockingReadStage<0>(dpu);
      process(*dpu);
      pipeline.blockingWriteStage<0>(ticket, dpu);
    }
  });
}

folly::Future<folly::Unit>
Normalizer::toBdd(Rule& rule) {
  rule.hs = HeaderSpace::fromInt(rule.bits, rule.prefixLength);
  return folly::Unit();
}

void
Normalizer::process(DataPlaneUpdate& dpu) {
  std::vector<folly::Future<folly::Unit>> futures;
  // HeaderSpace::locker.lock();
  // tbb::parallel_for(
  //     tbb::blocked_range<int>(0, dpu.added.size()),
  //     [&](tbb::blocked_range<int> br) {
  //       for (auto i = br.begin(); i < br.end(); ++i) {
  //         auto rule = dpu.added[i];
  //         rule->hs = HeaderSpace::fromInt(rule->bits, rule->prefixLength);
  //       }
  //     });
  std::for_each(
      // std::execution::par,
      std::execution::par_unseq,
      dpu.added.begin(),
      dpu.added.end(),
      [&](auto rule) {
        rule->hs = HeaderSpace::fromInt(rule->bits, rule->prefixLength);
        // folly::Future<folly::Unit> f =
        //     folly::via(&executor_, std::bind(toBdd, std::ref(rule)));
        // futures.push_back(std::move(f));
      });
  // for (auto& rule : dpu.added) {
  //   // rule.hs = HeaderSpace::fromInt(rule.addr, rule.prefixLength);
  //   folly::Future<folly::Unit> f =
  //       folly::via(&executor_, std::bind(toBdd, std::ref(rule)));

  //   // folly::Future<folly::Unit> f = folly::via(
  //   //     &executor_,
  //   //     [&rule](){
  //   //       rule.hs = HeaderSpace::fromInt(rule.addr, rule.prefixLength);
  //   //     });
  //   futures.push_back(std::move(f));
  // }
  // folly::collectAll(futures.begin(), futures.end());
  // HeaderSpace::locker.unlock();
}

} // namespace flashpp